Hadirkan pengalaman web yang lancar seperti aplikasi. Panduan komprehensif ini menjelajahi pseudo-element CSS View Transition yang kuat untuk menata transisi halaman dinamis, dengan contoh praktis dan praktik terbaik.
Menguasai Transisi Tampilan CSS: Kupas Tuntas Styling Pseudo-Element
Dalam lanskap pengembangan web yang terus berkembang, pencarian pengalaman pengguna yang mulus, lancar, dan menarik adalah sebuah hal yang konstan. Selama bertahun-tahun, para pengembang telah berusaha keras untuk menjembatani kesenjangan antara web dan aplikasi native, terutama dalam hal kelancaran transisi halaman. Navigasi web tradisional sering kali menghasilkan pemuatan ulang halaman penuh yang kasar—layar putih kosong yang sejenak memecah imersi pengguna. Aplikasi Satu Halaman (SPA) telah mengurangi masalah ini, tetapi membuat transisi kustom yang bermakna tetap menjadi tugas yang kompleks dan sering kali rapuh, sangat bergantung pada pustaka JavaScript dan manajemen state yang rumit.
Masuklah API Transisi Tampilan CSS (CSS View Transitions API), sebuah teknologi pengubah permainan yang siap merevolusi cara kita menangani perubahan UI di web. API yang kuat ini menyediakan mekanisme yang sederhana namun sangat fleksibel untuk menganimasikan antara status DOM yang berbeda, membuatnya lebih mudah dari sebelumnya untuk menciptakan pengalaman yang apik seperti aplikasi yang diharapkan pengguna. Inti dari kekuatan API ini terletak pada serangkaian pseudo-element CSS baru. Ini bukan pemilih (selector) biasa; mereka adalah elemen dinamis dan sementara yang dihasilkan oleh browser untuk memberi Anda kontrol terperinci atas setiap fase transisi. Panduan ini akan membawa Anda menyelami lebih dalam pohon pseudo-element ini, menjelajahi cara menata setiap komponen untuk membangun animasi yang menakjubkan, beperforma tinggi, dan dapat diakses untuk audiens global.
Anatomi Transisi Tampilan
Sebelum kita dapat menata sebuah transisi, kita harus memahami apa yang terjadi di balik layar saat transisi dipicu. Saat Anda memulai transisi tampilan (misalnya, dengan memanggil document.startViewTransition()), browser melakukan serangkaian langkah:
- Menangkap Status Lama: Browser mengambil "tangkapan layar" dari status halaman saat ini.
- Memperbarui DOM: Kode Anda kemudian membuat perubahan pada DOM (misalnya, menavigasi ke tampilan baru, menambah atau menghapus elemen).
- Menangkap Status Baru: Setelah pembaruan DOM selesai, browser mengambil tangkapan layar dari status baru.
- Membangun Pohon Pseudo-Element: Browser kemudian membangun pohon pseudo-element sementara di overlay halaman. Pohon ini berisi gambar yang ditangkap dari status lama dan baru.
- Menganimasikan: Animasi CSS diterapkan pada pseudo-element ini, menciptakan transisi yang mulus dari status lama ke yang baru. Defaultnya adalah cross-fade sederhana.
- Pembersihan: Setelah animasi selesai, pohon pseudo-element dihapus, dan pengguna dapat berinteraksi dengan DOM yang baru dan aktif.
Kunci dari kustomisasi adalah pohon pseudo-element sementara ini. Anggap saja ini sebagai satu set lapisan dalam alat desain, yang ditempatkan sementara di atas halaman Anda. Anda memiliki kontrol CSS penuh atas lapisan-lapisan ini. Berikut adalah struktur yang akan Anda gunakan:
- ::view-transition
- ::view-transition-group(*)
- ::view-transition-image-pair(*)
- ::view-transition-old(*)
- ::view-transition-new(*)
- ::view-transition-image-pair(*)
- ::view-transition-group(*)
Mari kita uraikan apa yang diwakili oleh masing-masing pseudo-element ini.
Pemeran Pseudo-Element
::view-transition: Ini adalah akar dari keseluruhan struktur. Ini adalah elemen tunggal yang mengisi viewport dan berada di atas semua konten halaman lainnya. Ini bertindak sebagai wadah untuk semua grup yang bertransisi dan merupakan tempat yang bagus untuk mengatur properti transisi secara keseluruhan seperti durasi atau fungsi waktu (timing function).
::view-transition-group(*): Untuk setiap elemen transisi yang berbeda (diidentifikasi oleh properti CSS view-transition-name), sebuah grup dibuat. Pseudo-element ini bertanggung jawab untuk menganimasikan posisi dan ukuran kontennya. Jika Anda memiliki kartu yang bergerak dari satu sisi layar ke sisi lain, ::view-transition-group-lah yang sebenarnya bergerak.
::view-transition-image-pair(*): Bersarang di dalam grup, elemen ini bertindak sebagai wadah dan clipping mask untuk tampilan lama dan baru. Peran utamanya adalah mempertahankan efek seperti border-radius atau transform selama animasi dan untuk menangani animasi cross-fade default.
::view-transition-old(*): Ini mewakili "tangkapan layar" atau tampilan yang dirender dari elemen dalam status lamanya (sebelum perubahan DOM). Secara default, ini beranimasi dari opacity: 1 ke opacity: 0.
::view-transition-new(*): Ini mewakili "tangkapan layar" atau tampilan yang dirender dari elemen dalam status barunya (setelah perubahan DOM). Secara default, ini beranimasi dari opacity: 0 ke opacity: 1.
Akar: Menata Pseudo-Element ::view-transition
Pseudo-element ::view-transition adalah kanvas tempat seluruh animasi Anda dilukis. Sebagai wadah tingkat atas, ini adalah tempat yang ideal untuk mendefinisikan properti yang harus berlaku secara global untuk transisi. Secara default, browser menyediakan satu set animasi, tetapi Anda dapat dengan mudah menimpanya.
Misalnya, transisi default adalah cross-fade yang berlangsung selama 250 milidetik. Jika Anda ingin mengubah ini untuk setiap transisi di situs Anda, Anda dapat menargetkan pseudo-element akar:
::view-transition {
animation-duration: 500ms;
animation-timing-function: ease-in-out;
}
Aturan sederhana ini sekarang membuat semua fade halaman default memakan waktu dua kali lebih lama dan menggunakan kurva 'ease-in-out', memberi mereka nuansa yang sedikit berbeda. Meskipun Anda dapat menerapkan animasi kompleks di sini, umumnya paling baik digunakan untuk mendefinisikan waktu dan easing universal, membiarkan pseudo-element yang lebih spesifik menangani koreografi yang mendetail.
Pengelompokan dan Penamaan: Kekuatan `view-transition-name`
Secara langsung, tanpa kerja ekstra, API Transisi Tampilan menyediakan cross-fade untuk seluruh halaman. Ini ditangani oleh satu grup pseudo-element untuk akar (root). Kekuatan sebenarnya dari API ini terbuka ketika Anda ingin mentransisikan elemen spesifik dan individual di antara status. Misalnya, membuat thumbnail produk di halaman daftar tumbuh dan bergerak dengan mulus ke posisi gambar produk utama di halaman detail.
Untuk memberitahu browser bahwa dua elemen di berbagai status DOM secara konseptual sama, Anda menggunakan properti CSS view-transition-name. Properti ini harus diterapkan pada elemen awal dan elemen akhir.
/* Pada CSS halaman daftar */
.product-thumbnail {
view-transition-name: product-image;
}
/* Pada CSS halaman detail */
.main-product-image {
view-transition-name: product-image;
}
Dengan memberikan kedua elemen nama unik yang sama ('product-image' dalam kasus ini), Anda menginstruksikan browser: "Daripada hanya memudarkan halaman lama dan memunculkan halaman baru, buatlah transisi khusus untuk elemen spesifik ini." Browser sekarang akan menghasilkan ::view-transition-group(product-image) khusus untuk menangani animasinya secara terpisah dari fade akar. Ini adalah konsep fundamental yang memungkinkan efek transisi "morphing" atau "shared element" yang populer.
Catatan Penting: Untuk setiap momen selama transisi, view-transition-name harus unik. Anda tidak dapat memiliki dua elemen yang terlihat dengan nama yang sama pada saat yang bersamaan.
Styling Mendalam: Pseudo-Element Inti
Dengan elemen-elemen kita yang sudah diberi nama, sekarang kita bisa mendalami styling pseudo-element spesifik yang dihasilkan browser untuk mereka. Di sinilah Anda dapat membuat animasi yang benar-benar kustom dan ekspresif.
`::view-transition-group(name)`: Sang Penggerak
Tanggung jawab tunggal grup ini adalah bertransisi dari ukuran dan posisi elemen lama ke ukuran dan posisi elemen baru. Ini tidak berisi penampilan konten sebenarnya, hanya kotak pembatasnya. Anggap saja sebagai bingkai yang bergerak.
Secara default, browser menganimasikan properti transform dan width/height-nya. Anda dapat menimpanya untuk menciptakan efek yang berbeda. Misalnya, Anda bisa menambahkan busur pada gerakannya dengan menganimasikannya di sepanjang jalur melengkung, atau membuatnya membesar dan mengecil selama perjalanannya.
::view-transition-group(product-image) {
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
Dalam contoh ini, kita menerapkan fungsi easing tertentu hanya pada pergerakan gambar produk, membuatnya terasa lebih dinamis dan fisik, tanpa memengaruhi fade default dari sisa halaman.
`::view-transition-image-pair(name)`: Sang Pemotong dan Pemudar
Bersarang di dalam grup yang bergerak, image-pair menampung tampilan lama dan baru. Ini bertindak sebagai clipping mask, jadi jika elemen Anda memiliki border-radius, image-pair memastikan bahwa konten tetap terpotong dengan radius tersebut selama animasi ukuran dan posisi. Tugas utamanya yang lain adalah mengatur cross-fade default antara konten lama dan baru.
Anda mungkin ingin menata elemen ini untuk memastikan konsistensi visual atau untuk membuat efek yang lebih canggih. Properti kunci yang perlu dipertimbangkan adalah isolation: isolate. Ini sangat penting jika Anda berencana menggunakan efek mix-blend-mode canggih pada turunannya (lama dan baru), karena ini menciptakan konteks penumpukan (stacking context) baru dan mencegah blending memengaruhi elemen di luar grup transisi.
::view-transition-image-pair(product-image) {
isolation: isolate;
}
`::view-transition-old(name)` dan `::view-transition-new(name)`: Bintang Pertunjukan
Ini adalah pseudo-element yang mewakili penampilan visual elemen Anda sebelum dan sesudah perubahan DOM. Di sinilah sebagian besar pekerjaan animasi kustom Anda akan terjadi. Secara default, browser menjalankan animasi cross-fade sederhana pada mereka menggunakan opacity dan mix-blend-mode. Untuk membuat animasi kustom, Anda harus terlebih dahulu mematikan yang default.
::view-transition-old(name),
::view-transition-new(name) {
animation: none;
}
Setelah animasi default dinonaktifkan, Anda bebas menerapkan animasi Anda sendiri. Mari kita jelajahi beberapa pola umum.
Animasi Kustom: Geser (Slide)
Daripada cross-fade, mari kita buat konten sebuah wadah bergeser masuk. Misalnya, saat bernavigasi antar artikel, kita ingin teks artikel baru bergeser masuk dari kanan sementara teks lama bergeser keluar ke kiri.
Pertama, definisikan keyframes:
@keyframes slide-from-right {
from { transform: translateX(100%); }
to { transform: translateX(0); }
}
@keyframes slide-to-left {
from { transform: translateX(0); }
to { transform: translateX(-100%); }
}
Sekarang, terapkan animasi ini ke pseudo-element lama dan baru untuk elemen bernama 'article-content'.
::view-transition-old(article-content) {
animation: 300ms ease-out forwards slide-to-left;
}
::view-transition-new(article-content) {
animation: 300ms ease-out forwards slide-from-right;
}
Animasi Kustom: Balik 3D (3D Flip)
Untuk efek yang lebih dramatis, Anda dapat membuat efek balik kartu 3D. Ini memerlukan animasi properti transform dengan rotateY dan juga mengelola backface-visibility.
/* Grup memerlukan konteks 3D */
::view-transition-group(card-flipper) {
transform-style: preserve-3d;
}
/* Image-pair juga perlu mempertahankan konteks 3D */
::view-transition-image-pair(card-flipper) {
transform-style: preserve-3d;
}
/* Tampilan lama berbalik dari 0 ke -180 derajat */
::view-transition-old(card-flipper) {
animation: 600ms ease-in forwards flip-out;
backface-visibility: hidden;
}
/* Tampilan baru berbalik dari 180 ke 0 derajat */
::view-transition-new(card-flipper) {
animation: 600ms ease-out forwards flip-in;
backface-visibility: hidden;
}
@keyframes flip-out {
from { transform: rotateY(0deg); }
to { transform: rotateY(-180deg); }
}
@keyframes flip-in {
from { transform: rotateY(180deg); }
to { transform: rotateY(0deg); }
}
Contoh Praktis dan Teknik Lanjutan
Teori itu berguna, tetapi aplikasi praktis adalah tempat kita benar-benar belajar. Mari kita telusuri beberapa skenario umum dan cara menyelesaikannya dengan pseudo-element transisi tampilan.
Contoh: Thumbnail Kartu yang "Berubah Bentuk" (Morphing)
Ini adalah transisi elemen bersama (shared element) yang klasik. Bayangkan sebuah galeri profil pengguna. Setiap profil adalah kartu dengan avatar. Saat Anda mengklik sebuah kartu, Anda menavigasi ke halaman detail di mana avatar yang sama ditampilkan secara menonjol di bagian atas.
Langkah 1: Beri Nama
Di halaman galeri Anda, gambar avatar diberi nama. Nama tersebut harus unik untuk setiap kartu, misalnya, berdasarkan ID pengguna.
/* Dalam gallery-item.css */
.card-avatar { view-transition-name: avatar-user-123; }
Di halaman detail profil, avatar header besar mendapatkan nama yang sama persis.
/* Dalam profile-page.css */
.profile-header-avatar { view-transition-name: avatar-user-123; }
Langkah 2: Kustomisasi Animasi
Secara default, browser akan memindahkan dan menskalakan avatar, tetapi juga akan melakukan cross-fade pada konten. Jika gambarnya identik, fade ini tidak perlu dan dapat menyebabkan sedikit kedipan. Kita bisa menonaktifkannya.
/* Tanda bintang (*) di sini adalah wildcard untuk setiap grup bernama */
::view-transition-image-pair(*) {
/* Nonaktifkan fade default */
animation-duration: 0s;
}
Tunggu, jika kita menonaktifkan fade, bagaimana kontennya beralih? Untuk elemen bersama di mana tampilan lama dan baru identik, browser cukup pintar untuk hanya menggunakan satu tampilan untuk seluruh transisi. `image-pair` pada dasarnya hanya menampung satu gambar, jadi menonaktifkan fade hanya mengungkapkan optimisasi ini. Untuk elemen di mana kontennya benar-benar berubah, Anda akan memerlukan animasi kustom sebagai pengganti fade default.
Menangani Perubahan Rasio Aspek
Tantangan umum muncul ketika elemen yang bertransisi mengubah rasio aspeknya. Misalnya, thumbnail lanskap 16:9 di halaman daftar mungkin bertransisi menjadi avatar persegi 1:1 di halaman detail. Perilaku default browser adalah menganimasikan lebar dan tinggi secara independen, yang mengakibatkan gambar tampak penyet atau meregang selama transisi.
Solusinya elegan. Kita biarkan ::view-transition-group menangani perubahan ukuran dan posisi, tetapi kita menimpa styling gambar lama dan baru di dalamnya.
Tujuannya adalah membuat "tangkapan layar" lama dan baru mengisi wadahnya tanpa distorsi. Kita dapat melakukan ini dengan mengatur lebar dan tingginya menjadi 100% dan membiarkan properti object-fit default browser (yang diwarisi dari elemen asli) menangani penskalaan dengan benar.
::view-transition-old(hero-image),
::view-transition-new(hero-image) {
/* Mencegah distorsi dengan mengisi wadah */
width: 100%;
height: 100%;
/* Timpa cross-fade default untuk melihat efeknya dengan jelas */
animation: none;
}
Dengan CSS ini, `image-pair` akan menganimasikan rasio aspeknya dengan mulus, dan gambar di dalamnya akan dipotong atau diberi letterbox dengan benar (tergantung pada nilai `object-fit` mereka), sama seperti di dalam wadah normal. Anda kemudian dapat menambahkan animasi kustom Anda sendiri, seperti cross-fade, di atas geometri yang sudah diperbaiki ini.
Debugging dan Dukungan Browser
Menata elemen yang hanya ada selama sepersekian detik bisa jadi rumit. Untungnya, browser modern menyediakan alat pengembang yang sangat baik untuk ini. Di Chrome atau Edge DevTools, Anda bisa pergi ke panel "Animations", dan saat Anda memicu transisi tampilan, Anda bisa menjedanya. Dengan animasi dijeda, Anda kemudian dapat menggunakan panel "Elements" untuk memeriksa seluruh pohon pseudo-element `::view-transition` seperti bagian lain dari DOM. Anda dapat melihat gaya yang diterapkan dan bahkan memodifikasinya secara real-time untuk menyempurnakan animasi Anda.
Hingga akhir tahun 2023, API Transisi Tampilan didukung di browser berbasis Chromium (Chrome, Edge, Opera). Implementasi sedang berlangsung untuk Firefox dan Safari. Ini menjadikannya kandidat yang sempurna untuk peningkatan progresif (progressive enhancement). Pengguna dengan browser yang didukung mendapatkan pengalaman yang menyenangkan dan ditingkatkan, sementara pengguna di browser lain mendapatkan navigasi instan standar. Anda dapat memeriksa dukungan di CSS:
@supports (view-transition: none) {
/* Semua gaya view-transition diletakkan di sini */
::view-transition-old(my-element) { ... }
}
Praktik Terbaik untuk Audiens Global
Saat mengimplementasikan animasi, sangat penting untuk mempertimbangkan beragam pengguna dan perangkat di seluruh dunia.
Performa: Animasi harus cepat dan lancar. Tetaplah menganimasikan properti CSS yang murah untuk diproses oleh browser, terutama transform dan opacity. Menganimasikan properti seperti width, height, atau margin dapat memicu kalkulasi ulang tata letak pada setiap frame, yang menyebabkan tersendat-sendat dan pengalaman yang buruk, terutama pada perangkat berdaya rendah.
Aksesibilitas: Beberapa pengguna mengalami mabuk gerak atau ketidaknyamanan dari animasi. Semua sistem operasi utama menyediakan preferensi pengguna untuk mengurangi gerakan. Kita harus menghormati ini. Media query prefers-reduced-motion memungkinkan Anda untuk menonaktifkan atau menyederhanakan animasi Anda untuk para pengguna ini.
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
/* Lewati semua animasi kustom dan gunakan fade cepat dan sederhana */
animation: none !important;
}
}
Pengalaman Pengguna (UX): Transisi yang baik memiliki tujuan. Mereka harus memandu perhatian pengguna dan memberikan konteks tentang perubahan yang terjadi di UI. Animasi yang terlalu lambat dapat membuat aplikasi terasa lamban, sementara yang terlalu mencolok bisa mengganggu. Usahakan durasi transisi antara 200ms dan 500ms. Tujuannya adalah agar animasi lebih terasa daripada terlihat.
Kesimpulan: Masa Depan yang Lancar
API Transisi Tampilan CSS, dan khususnya pohon pseudo-elementnya yang kuat, merupakan lompatan monumental ke depan untuk antarmuka pengguna web. Ini memberi pengembang seperangkat alat bawaan, beperforma tinggi, dan sangat dapat disesuaikan untuk menciptakan jenis transisi yang lancar dan stateful yang dulunya merupakan domain eksklusif aplikasi native. Dengan memahami peran ::view-transition, ::view-transition-group, dan pasangan gambar lama/baru, Anda dapat melampaui fade sederhana dan merancang koreografi animasi yang rumit dan bermakna yang meningkatkan kegunaan dan menyenangkan pengguna.
Seiring meluasnya dukungan browser, API ini akan menjadi bagian penting dari perangkat pengembang front-end modern. Dengan merangkul kemampuannya dan mematuhi praktik terbaik untuk performa dan aksesibilitas, kita dapat membangun web yang tidak hanya lebih fungsional tetapi juga lebih indah dan intuitif untuk semua orang, di mana saja.